package com.rtsapp.agent;

import com.rtsapp.server.logger.Logger;
import com.rtsapp.server.logger.LoggerFactory;
import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;

import java.io.IOException;
import java.lang.instrument.Instrumentation;
import java.lang.management.ManagementFactory;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Created by liwang on 17-3-31.
 */
class AgentLoader {

    private static final Logger LOGGER = LoggerFactory.getLogger( AgentLoader.class );

    private static final AtomicBoolean loaded = new AtomicBoolean( false );

    private static LoadAgentCallBack callBack = null;

    // 配合pom文件中的manifest描述, 同时支持两种代理
    public static void agentmain( String arg, Instrumentation inst ) {
        premain( arg, inst );
    }

    // 配合pom文件中的manifest描述, 同时支持两种代理
    public static void premain( String arg, Instrumentation inst ) {
        HotfixService.AGENT_HANDLER.initialize( inst );
    }

    /**
     * 使用 VirtualMachine.attach 加载代理
     * agentmain方法将被调用
     *
     * @return 此方法只能调用一次, 返回false表示执行出错或者重复调用
     */
    public static void loadAgent( LoadAgentCallBack callBack ) {

        LOGGER.info( "rts-hotfix:  开始执行 AgentLoader.loadAgent()" );

        if ( !loaded.compareAndSet( false, true ) ) {
            LOGGER.error( "rts-hotfix:  AgentLoader.loadAgent()已经执行过!" );
            return;
        }

        AgentLoader.callBack = callBack;

        // 启动agent
        String pid = ManagementFactory.getRuntimeMXBean( ).getName( ).split( "@" )[ 0 ];
        try {

            VirtualMachine vm = VirtualMachine.attach( pid );
            vm.loadAgent( System.getProperty( "java.class.path" ) );
            vm.detach( );

            return;
        } catch ( AttachNotSupportedException e ) {
            LOGGER.error( e, "rts-hotfix:  当前运行环境不支持使用VirtualMachine !" );
        } catch ( IOException e ) {
            LOGGER.error( e, "rts-hotfix:  VirtualMachine.attach( {} )出现未知问题!", pid );
        } catch ( AgentLoadException e ) {
            LOGGER.error( e );
        } catch ( AgentInitializationException e ) {
            LOGGER.error( e );
        } catch ( Throwable e ) {
            LOGGER.error( e, "rts-hotfix:  AgentLoader.loadAgent() 发生未知错误!" );
        }

        // 如果执行到这里, 说明执行出错, 调用callBack
        callBack.callBack( null );
    }

    public interface LoadAgentCallBack {
        void callBack( Instrumentation inst );
    }
}
